package com.permissionmanager.common;

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.permissionmanager.entity.User;
import com.permissionmanager.exception.ServiceException;
import com.permissionmanager.mapper.UserMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * 定义拦截的规则
 *
 */
public class JwtInterceptor implements HandlerInterceptor {

    @Resource
    private UserMapper userMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse rep, Object handler) throws Exception {
        String token = request.getHeader("token");
        // 如果头部不存在token
        if (StrUtil.isBlank(token)) {
            token = request.getParameter("token");// 其url里面找
        }


        // 如果都token不存在，就输出 401（权限错误）
        if (StrUtil.isBlank(token)) {
            throw new ServiceException("401","请登录");
        }

        // 如果存在，获取token中user的id
        String userId;
        // 进行解码
        try {
            userId = JWT.decode(token).getAudience().get(0);  // 解码
        } catch (JWTDecodeException j) {
            throw new ServiceException("401","请登录");
        }

        // 根据token中的userId查询数据库
        User user = userMapper.findByUser(Integer.parseInt(userId),null,null);
        // 如果user为null
        if (user == null) {
            throw new ServiceException("401","请登录");
        }

        // 用密码加密验证token
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            // 尝试验证token
            jwtVerifier.verify(token);
        }catch (JWTVerificationException j){
            throw new ServiceException("401","请登录");
        }

        return true;
    }
}